package edu.ustb.mis.excel.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import com.google.common.collect.Lists;
import edu.ustb.mis.dm.Constants;
import edu.ustb.mis.dm.util.NullHandlerUtils;
import edu.ustb.mis.excel.annotation.Excel;
import edu.ustb.mis.excel.style.ExcelStyleUtils;
import edu.ustb.mis.exception.ServiceException;

public class ExcelExporter<T> {
	// 格式化日期
	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	/**
	 * @param title 标题
	 * @param dataset 集合
	 * @param out 输出流
	 */
	public Workbook exportExcel(final String title, final Collection<T> dataset, final String excelType) throws Exception {
		// 声明一个工作薄
		// 首先检查数据看是否是正确的
		final Iterator<T> its = dataset.iterator();
		if ( (dataset == null) || !its.hasNext() || (title == null)) {
			throw new ServiceException("传入的数据不对！");
		}
		// 取得实际泛型类
		final T ts = its.next();
		final Class<? extends Object> tCls = ts.getClass();
		final Workbook workbook = excelType.equals("2003") ? new HSSFWorkbook() : new XSSFWorkbook();
		// 生成一个表格
		final Sheet sheet = workbook.createSheet(title);
		// 设置表格默认列宽度为15个字节
		sheet.setDefaultColumnWidth(15);
		// 生成一个样式
		CellStyle style = workbook.createCellStyle();
		// 设置标题样式
		style = ExcelStyleUtils.setHeadStyle(workbook, style);
		// 得到所有字段
		final Field filed[] = ts.getClass().getDeclaredFields();
		// 标题
		final List<String> exportfieldtile = Lists.newArrayList();
		// 导出的字段的get方法
		final List<Method> methodObj = Lists.newArrayList();
		// 遍历整个filed
		for (final Field f : filed) {
			final Excel exa = f.getAnnotation(Excel.class);
			// 如果设置了annottion
			if (exa != null) {
				final String exprot = exa.exportName();
				// 添加到标题
				exportfieldtile.add(exprot);
				// 添加到需要导出的字段的方法
				final String fieldname = f.getName();
				final String getMethodName = "get" + fieldname.substring(0, 1).toUpperCase() + fieldname.substring(1);
				final Method getMethod = tCls.getMethod(getMethodName, new Class[]{});
				methodObj.add(getMethod);
			}
		}
		// 产生表格标题行
		Row row = sheet.createRow(0);
		if (excelType.equals("2003")) {
			for (int i = 0; i < exportfieldtile.size(); i++) {
				final Cell cell = row.createCell(i);
				cell.setCellStyle(style);
				final RichTextString text = new HSSFRichTextString(exportfieldtile.get(i));
				cell.setCellValue(text);
			}
		} else {
			for (int i = 0; i < exportfieldtile.size(); i++) {
				final Cell cell = row.createCell(i);
				cell.setCellStyle(style);
				final RichTextString text = new XSSFRichTextString(exportfieldtile.get(i));
				cell.setCellValue(text);
			}
		}
		int index = 0;
		// 循环整个集合
		for (final T t : dataset) {
			index++;
			row = sheet.createRow(index);
			for (int k = 0; k < methodObj.size(); k++) {
				final Cell cell = row.createCell(k);
				final Method getMethod = methodObj.get(k);
				final Object value = getMethod.invoke(t, new Object[]{});
				setValue(value, cell);
			}
		}
		return workbook;
	}

	public void setValue(final Object value, final Cell cell) {
		if (value == null) {
			cell.setCellValue(Constants.BLANK);
		} else if (value instanceof Boolean) {
			cell.setCellValue((Boolean)value ? "是" : "否");
		} else if (value instanceof Date) {
			cell.setCellValue(sdf.format((Date)value));
		} else if (value instanceof String) {
			cell.setCellValue((String)value);
		} else {
			cell.setCellValue(NullHandlerUtils.NullToDouble(value));
		}
	}
}
